package xyz.jcat.sco.gateway.oauth2;

import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.server.resource.BearerTokenError;
import org.springframework.security.web.server.ServerAuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import xyz.jcat.common.util.JsonUtils;
import xyz.jcat.common.web.Resp;

@Component
public class ServerAuthenticationEntryPointImpl implements ServerAuthenticationEntryPoint {

    @Override
    public Mono<Void> commence(ServerWebExchange serverWebExchange, AuthenticationException e) {
        HttpStatus httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
        String message = null;
        if(e instanceof OAuth2AuthenticationException) {
            OAuth2AuthenticationException oAuth2AuthenticationException = (OAuth2AuthenticationException) e;
            BearerTokenError error = (BearerTokenError)oAuth2AuthenticationException.getError();
//            //TODO token过期 刷新token
//            if((oAuth2AuthenticationException.getCause() instanceof JwtValidationException)
//                && error.getDescription().startsWith(ERROR_DESCRIPTION_PREFIX_TOKEN_EXPIRED)) {
//
//            }
            httpStatus = error.getHttpStatus();
            message = error.getErrorCode();
        } else if(e instanceof AuthenticationCredentialsNotFoundException) {
            httpStatus = HttpStatus.UNAUTHORIZED;
            message = e.getMessage();
        }
        ServerHttpResponse response = serverWebExchange.getResponse();
        if (response.isCommitted()) {
            return Mono.error(e);
        }
        Resp resp = new Resp(httpStatus.value(), message);
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        response.setStatusCode(httpStatus);
        return response
                .writeWith(Mono.fromSupplier(() -> {
                    DataBufferFactory bufferFactory = response.bufferFactory();
                    return bufferFactory.wrap(JsonUtils.toString(resp).getBytes());
                }));
    }
}
